unsigned short ip_fast_csum(unsigned char * iph,
unsigned int ihl)
{
unsigned int sum;

__asm__ __volatile__(
    "movl (%1), %0 ;\n"
    "subl $4, %2 ;\n"
    "jbe 2f ;\n"
    "addl 4(%1), %0 ;\n"
    "adcl 8(%1), %0 ;\n"
    "adcl 12(%1), %0 ;\n"
    "1: adcl 16(%1), %0 ;\n"
    "lea 4(%1), %1 ;\n"
    "decl %2 ;\n"
    "jne 1b ;\n"
    "adcl $0, %0 ;\n"
    "movl %0, %2 ;\n"
    "shrl $16, %0 ;\n"
    "addw %w2, %w0 ;\n"
    "adcl $0, %0 ;\n"
    "notl %0 ;\n"
    "2: ;\n"
    /* Since the input registers which are loaded with iph and ihl
    are modified, we must also specify them as outputs, or gcc
    will assume they contain their original values. */
    : "=r" (sum), "=r" (iph), "=r" (ihl)
    : "1" (iph), "2" (ihl)
    : "memory");
    return(sum);
} 
static u_int16_t checksum(u_int32_t init, u_int8_t *addr, size_t count){ 
    /* Compute Internet Checksum for "count" bytes * beginning at location "addr". */ 
    u_int32_t sum = init; 

    while( count > 1 ) { 
        /* This is the inner loop */
        sum += ntohs(* (u_int16_t*) addr);
        addr += 2;
        count -= 2;
    } /* Add left-over byte, if any */
    if( count > 0 )
        sum += ntohs(* (u_int8_t*) addr); /* Fold 32-bit sum to 16 bits */ 
    while (sum>>16)
    sum = (sum & 0xffff) + (sum >> 16); 
    return (u_int16_t)~sum;
} 
static u_int16_t tcp_checksum2(struct iphdr* iphdrp, struct tcphdr* tcphdrp){ 
    size_t tcplen = ntohs(iphdrp->tot_len) - (iphdrp->ihl<<2); 
    u_int32_t cksum = 0;

    cksum += ntohs((iphdrp->saddr >> 16) & 0x0000ffff);
    cksum += ntohs(iphdrp->saddr & 0x0000ffff);
    cksum += ntohs((iphdrp->daddr >> 16) & 0x0000ffff);
    cksum += ntohs(iphdrp->daddr & 0x0000ffff);
    cksum += iphdrp->protocol & 0x00ff;
    cksum += tcplen; 
    return checksum(cksum, (u_int8_t*)tcphdrp, tcplen);
} 

static u_int16_t tcp_checksum1(struct iphdr* iphdrp){ 
    struct tcphdr *tcphdrp = (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2)); 
    return tcp_checksum2(iphdrp, tcphdrp);
} 
static void set_tcp_checksum2(struct iphdr* iphdrp, struct tcphdr* tcphdrp){
    tcphdrp->check = 0;
    tcphdrp->check = htons(tcp_checksum2(iphdrp, tcphdrp));
} 
static void set_tcp_checksum1(struct iphdr* iphdrp){ 
    struct tcphdr *tcphdrp = (struct tcphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
    set_tcp_checksum2(iphdrp, tcphdrp);
}

static u_int16_t udp_checksum2(struct iphdr* iphdrp, struct udphdr* udphdrp){ 
    size_t udplen = ntohs(iphdrp->tot_len) - (iphdrp->ihl<<2); 
    u_int32_t cksum = 0;

    cksum += ntohs((iphdrp->saddr >> 16) & 0x0000ffff);
    cksum += ntohs(iphdrp->saddr & 0x0000ffff);
    cksum += ntohs((iphdrp->daddr >> 16) & 0x0000ffff);
    cksum += ntohs(iphdrp->daddr & 0x0000ffff);
    cksum += iphdrp->protocol & 0x00ff;
    cksum += udplen; 
    return checksum(cksum, (u_int8_t*)udphdrp, udplen);
} 

static u_int16_t udp_checksum1(struct iphdr* iphdrp){ 
    struct udphdr *udphdrp = (struct udphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2)); 
    return udp_checksum2(iphdrp, udphdrp);
} 
static void set_udp_checksum2(struct iphdr* iphdrp, struct udphdr* udphdrp){
    udphdrp->check = 0;
    udphdrp->check = htons(udp_checksum2(iphdrp, udphdrp));
}
static void set_udp_checksum1(struct iphdr* iphdrp){ 
    struct udphdr *udphdrp = (struct udphdr*)((u_int8_t*)iphdrp + (iphdrp->ihl<<2));
    set_udp_checksum2(iphdrp, udphdrp);
}